﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using FotoAlbum.Async;
using FotoAlbum.Sort;

namespace FotoAlbum
{
    public partial class FormJ : Form
    {
        private readonly LoaderAsync _loader;
        //private readonly CancellationTokenSource _cancellationToken;
        private readonly List<FICompare> _items = new List<FICompare>();

        public FormJ()
        {
            InitializeComponent();
            InitializeDebugComponents();
            //_cancellationToken = new CancellationTokenSource();
            _loader = new LoaderAsync();
            _loader.SingleImageLoadedEvent += SingleImageLoadedEvent;
            _loader.LoadingCompleted += ImageLoadingCompleted;
            listView1.SetDoubleBuffered(true);
        }

        #region Debug
        /// <summary>
        /// Components that should sololy be used in Debug mode.
        /// </summary>
        private void InitializeDebugComponents()
        {
#if DEBUG
            var itemA = new ToolStripMenuItem("Annuleren");
            //itemA.Click += AnnulerenClick;

            var itemB = new ToolStripMenuItem("ProgressBar");
            itemB.Click += new EventHandler((a, b) => { System.Diagnostics.Debug.WriteLine(toolStripProgressBar1.Minimum + "/" + toolStripProgressBar1.Value + "/" + toolStripProgressBar1.Maximum); });

            var item = new ToolStripMenuItem("Debug");
            item.DropDownItems.AddRange(new ToolStripMenuItem[] { itemA, itemB });
            menuStrip1.Items.Add(item);

            // Jiri <3
            folderBrowserDialog1.RootFolder = Environment.SpecialFolder.MyComputer;  
#endif
        }
        #endregion

        /// <summary>
        /// Opens a dialog in which a folder can be selected.
        /// </summary>
        private void OpenClick(object sender, EventArgs e)
        {
            if  (folderBrowserDialog1.ShowDialog() == DialogResult.OK) 
            {
                _items.Clear();
                imageList1.Images.Clear();
                listView1.Items.Clear();
                FillImagesList(directory: folderBrowserDialog1.SelectedPath); // NOTE: Mark explain please...
            }
        }
        
        /// <summary>
        /// Fills the image list using images from the given directory.
        /// </summary>
        /// <param name="directory">The directory from where to load the images.</param>
        /// <remarks>Does not load sub-directories.</remarks>
        private void FillImagesList(string directory)
        {
            var di = new DirectoryInfo(directory);
            var fi = di.GetFilesByExtensions(".jpg", ".png", ".bmp", ".gif", ".tiff");
            _loader.LoadAsync(fi);
            toolStripProgressBar1.Maximum = Counter.Maximum;
        }

        /// <summary>
        /// Starts a new thread for the full sized image.
        /// </summary>
        private void listView1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            var thread = new Thread(FireEventBox) {Priority = ThreadPriority.Highest}; // Highest requires the process to be Realtime.
            thread.Start(listView1.SelectedItems[0].Name);
        }

        /// <summary>
        /// Creates a new Form that can be used to display the full sized image.
        /// </summary>
        private void FireEventBox(object filename)
        {
            using (var preview = new Preview((string)filename))
            {
                preview.ShowDialog();
            }
        }

        /// <summary>
        /// Called when a single image has been loaded.
        /// </summary>
        private void SingleImageLoadedEvent(LoaderEventArgs e)
        {
            if (InvokeRequired)
            {
                Invoke(new Action<LoaderEventArgs>(SingleImageLoadedEvent), e);
            }
            else
            {
                if (e.Id < Counter.AbortAt)
                    return;

                UpdateProgressBar();
                imageList1.Images.Add(e.Path, e.Image);
                if (e.Name.Contains(searchTextBox.Text))
                {
                    listView1.Items.Add(e.Path, e.Name, imageList1.Images.IndexOfKey(e.Path));
                    listView1.Update();
                }

                // Add them to the list so we can sort them.
                _items.Add(e.Info);

                toolStripStatusLabel1.Text = "Loading...";
            }
        }

        /// <summary>
        /// Called when all the images have been loaded.
        /// </summary>
        private void ImageLoadingCompleted()
        {
            if (InvokeRequired)
            {
                Invoke(new Action(ImageLoadingCompleted));
            }
            else
            {
                //Counter.Reset();
                UpdateProgressBar();
                toolStripStatusLabel1.Text = "Loading completed";
            }
        }

        /// <summary>
        /// Update the progress bar on the tool strip.
        /// </summary>
        private void UpdateProgressBar()
        {
            toolStripProgressBar1.Minimum = (Counter.AbortAt == -1) ? 0 : Counter.AbortAt;
            toolStripProgressBar1.Maximum = Counter.Maximum;

            // Tends to be sensitive due to the use of different threads; so check it first!
            toolStripProgressBar1.Value = (Counter.Current < toolStripProgressBar1.Minimum) ? toolStripProgressBar1.Minimum : ((Counter.Current > toolStripProgressBar1.Maximum) ? toolStripProgressBar1.Maximum : Counter.Current);
        }

        /// <summary>
        /// Called when a key has been pressed in the search box.
        /// </summary>
        private void searchTextBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            // Only display the result when the ENTER key has been pressed.
            if (e.KeyChar == (char)Keys.Enter)
            {
                DisplayItems();
            }
        }

        /// <summary>
        /// Sort and display the items.
        /// </summary>
        private void DisplayItems()
        {
            // Sort the items first!
            Sort();

            // Update the list.
            listView1.BeginUpdate();
            listView1.Items.Clear();
            foreach (FICompare item in _items)
            {
                if (item.Name.Contains(searchTextBox.Text))
                {
                    listView1.Items.Add(item.Path, item.Name, imageList1.Images.IndexOfKey(item.Path));
                }
            }
            listView1.EndUpdate();
        }
    }
}
